Skip to content

Phase 6.3: TCP window management — track guest window, advertise host kernel rcv-space#75

Closed
dpsoft wants to merge 10 commits intosmoltcp-passt-port-phase6.2-async-connectfrom
smoltcp-passt-port-phase6.3-window-mgmt
Closed

Phase 6.3: TCP window management — track guest window, advertise host kernel rcv-space#75
dpsoft wants to merge 10 commits intosmoltcp-passt-port-phase6.2-async-connectfrom
smoltcp-passt-port-phase6.3-window-mgmt

Conversation

@dpsoft
Copy link
Copy Markdown
Contributor

@dpsoft dpsoft commented May 5, 2026

Status: DRAFT. Stacked on PR #74 (Phase 6.2 async connect).

What this branch does

Stops ignoring the guest's advertised window and stops hardcoding our own.

  • `TcpNatEntry` tracks per-flow `guest_window: u32` + `guest_window_scale: u8`.
  • `handle_tcp_frame` parses the WindowScale option from guest SYN, stashes it; updates `guest_window` on every incoming frame.
  • `build_tcp_packet_static` signature now takes `(window_len, window_scale)` — caller decides per frame.
  • SYN-ACK negotiates `window_scale: Some(7)` (passt's default; 128× scaling, extends window from 64 KiB to 8 MiB).
  • `relay_tcp_nat_data` gates host→guest sends on `entry.guest_window` so the guest sees real backpressure.
  • Outgoing frames advertise `host_recv_window(fd)` — derived from `getsockopt(TCP_INFO).tcpi_rcv_space` — instead of a hardcoded 65535.

Severity

Medium — perf gap. Today the relay emits `window_len: 65535, window_scale: None` on every outgoing frame, ignores the guest's advertised window entirely, and never honors guest backpressure. Throughput is capped at 64 KB / RTT regardless of bandwidth, and `inject_to_guest` could grow unbounded if the guest is slow.

Bench evidence (`bench-compare.sh --baseline 47868f0 --skip-vm`)

Bench Baseline HEAD Note
`tcp_bulk_throughput_constrained_window/4096` 2.65 ms new
`tcp_bulk_throughput_constrained_window/16384` 1.89 ms new
`tcp_bulk_throughput_constrained_window/65536` 1.77 ms new
`tcp_inbound_syn_ack_transition` 68 µs 51.6 µs -24%
`process_syn` 33 µs 28 µs -15%
`tcp_bulk_throughput_1mb` 62 ms 61.7 ms parity
`poll_with_n_mixed_flows/999` 299 µs 10.1 µs -97 % held
`port_forward_accept_latency` 50.1 ms 206 µs held from #72

Wall-clock vs master

Metric Master This branch Δ
TCP g2h throughput 1885 Mbps 5320 Mbps +182 % (2.8×)
TCP bulk-g2h 1565 Mbps 4775 Mbps +205 % (3.0×)
TCP CRR p50 ~10 ms ~10.1 ms parity
TCP RR p50 2 µs 2 µs parity

Commits (10 + plan)

  1. `b8772ca` — docs: Phase 6.3 TDD plan
  2. `655f01f` — feat: TcpNatEntry tracks guest_window + guest_window_scale
  3. `f4ff6a2` — feat: parse guest's window_scale on SYN, store on flow
  4. `2260c61` — feat: track guest's advertised window on every incoming frame
  5. `6541ba7` — refactor: build_tcp_packet_static takes (window_len, window_scale)
  6. `b46085c` — feat: advertise host-kernel-derived window on outgoing frames
  7. `b8d6716` — test: pin tcp_advertised_window_tracks_guest_buffer (BROKEN_ON_PURPOSE → flips at Supress macOS warnings #7)
  8. `e74cf83` — feat: gate host→guest send on guest's advertised window
  9. `a0cd92f` — test: pin tcp_window_scale_negotiated_in_synack
  10. `aad52d9` — bench: tcp_bulk_throughput_constrained_window parametric

Validation

Suite Status
`cargo fmt --all -- --check`
`cargo clippy --workspace --all-targets --all-features -- -D warnings`
`cargo test --test network_baseline` ✅ 24/24
`cargo test --test network_baseline --features bench-helpers -- --test-threads=1` ✅ 26/26
`cargo test --lib network` ✅ 25/25
`cargo bench --bench network --features bench-helpers --no-run`
`cargo build --release`

dpsoft added 10 commits May 5, 2026 08:49
10 bite-sized tasks covering proper TCP windowing:

- TcpNatEntry tracks guest_window (u32) + guest_window_scale (u8)
- handle_tcp_frame parses tcp.window_scale() on guest SYN, stores
  per-flow; updates guest_window on every incoming frame
- build_tcp_packet_static signature changes to take
  (window_len, window_scale) — caller decides
- SYN-ACK negotiates OUR_WINDOW_SCALE = 7 (passt's default; 128x)
- New host_recv_window helper queries TCP_INFO.tcpi_rcv_space and
  scales it for the advertised window on outgoing frames
- relay_tcp_nat_data gates host→guest sends on entry.guest_window
  to honor real backpressure
- Three new pins: tcp_advertised_window_tracks_guest_buffer
  (BROKEN_ON_PURPOSE → flips at Task 7),
  tcp_window_scale_negotiated_in_synack, plus
  tcp_bulk_throughput_constrained_window parametric bench

Severity: MEDIUM — perf gap. Hardcoded window_len: 65535 caps
throughput at 64 KB / RTT regardless of bandwidth, and
inject_to_guest can grow unbounded if the guest is slow.
Adds tcp_bulk_throughput_constrained_window bench that exercises the
Task 7 window-gating path under three guest-window sizes (4096, 16384,
65536 bytes). Mirrors tcp_bulk_throughput_1mb with a parametric window
so regressions in window-constrained relay show up numerically.
@dpsoft
Copy link
Copy Markdown
Contributor Author

dpsoft commented May 6, 2026

Superseded by #79 (Phase 6.3 cherry-picked clean onto post-#78 main).

@dpsoft dpsoft closed this May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant